home *** CD-ROM | disk | FTP | other *** search
/ Aminet 22 / Aminet 22 (1997)(GTI - Schatztruhe)[!][Dec 1997].iso / Aminet / dev / e / ebuild.lha / ebuild / Build.e < prev    next >
Text File  |  1997-09-21  |  12KB  |  433 lines

  1. /* build in E.
  2.  
  3. TODO:    - cyclic structure check (part)
  4.     - (amigados?) constants (part)
  5.  
  6. */
  7.  
  8. OPT OSVERSION=37
  9.  
  10. MODULE 'tools/file', 'dos/dosextens', 'dos/dos'
  11.  
  12. /*
  13.   symbol=object
  14.   object: dep1 dep2 ....
  15.      act1
  16.      act2
  17.  
  18.   $(symbol): $(symbol)bla ....
  19.      act1
  20.      ...
  21. */
  22.  
  23. /*
  24. history:
  25.  
  26. (Version 0.8 by Rob and Wouter)
  27.  
  28. When        Who        What
  29. 23.07.97    Glauschwuffel    - Added symbolic constants. Constants are allowed everywhere
  30. 26.07.97    Glauschwuffel    - Removed bug in constants: The part after the last constant
  31.                   wouldn't be copied. $(test): $(test).e crashed in cyclic
  32.                   dependancy. :(
  33.                 - Used source that Jason mailed me to get right order of actions.
  34.                 - Minor modification in traverse(): "circ" is raised when object
  35.                   and a dependancy have the same name. 
  36.                 - Added version facility :)
  37.                 - local constant $(target) is now available in actions
  38.                 - Added QUIET arg
  39. 27.07.97    Glauschwuffel    - Changed QUIET to VERBOSE since quiet was default for v3.1
  40. (between        Glauschwuffel   - Used EBuild with new oomodules/ objects. *Very* stable, no errrors
  41.                                           at all. I tend to say it's error-free <g>)
  42. 09.08.97    Glauschwuffel    - Actions of a target are now collected in a script again.
  43.                                           EBuild now acts as described in the Ev3.2 doc (except of the
  44.                                           modified $target). Bumped version to 0.9.
  45. 10.08.97    Glauschwuffel    - Added script variable $target for reasons of consistency. Now
  46.                                           $(target) and $target are possible.
  47.                                           Discovered a potential bug: if build is called without a target and
  48.                                           the first target in the buildfile is not a filename (e.g. a symbolic
  49.                                   target like `all' or `clean') the actions for this target are
  50.                                   executed anyway (0.8 does this, too).
  51. 05.09.97    Glauschwuffel    - BUG: the temporary script in T: won't be closed if an exception
  52.                   raised. Removed.
  53. 13.09.97    Glauschwuffel    - ADD: commandline option CONSTANTS. Lists the constants before executing
  54.                   anything. Modified `dumpC()' for this.
  55. */
  56.  
  57. OBJECT object
  58.   next:PTR TO object
  59.   name:PTR TO CHAR
  60.   firstdep:PTR TO dependancy
  61.   firstaction:PTR TO action
  62.   child
  63.   lastaction:PTR TO action
  64. ENDOBJECT
  65.  
  66. OBJECT dependancy
  67.   next:PTR TO dependancy
  68.   object:PTR TO object
  69. ENDOBJECT
  70.  
  71. OBJECT action
  72.   next:PTR TO action
  73.   comstring:PTR TO CHAR
  74. ENDOBJECT
  75.  
  76. OBJECT arg
  77.   target,buildfile,force,verbose,nohead,constants
  78. ENDOBJECT
  79.  
  80. OBJECT constant
  81.   next:PTR TO constant
  82.   name:PTR TO CHAR
  83.   subst:PTR TO CHAR
  84. ENDOBJECT
  85.  
  86. DEF curline=0, curstring, uptodate=TRUE, args:PTR TO arg,
  87.     constants:PTR TO constant, -> global list of constants in reverse order
  88.     target:PTR TO CHAR -> holds name of current target
  89.  
  90. PROC main() HANDLE
  91.   DEF m,l,buildfile[200]:STRING,rdargs=NIL
  92.   NEW args
  93.   IF (rdargs:=ReadArgs('TARGET,FROM/K,FORCE/S,VERBOSE/S,NOHEAD/S,CONSTANTS/S',args,NIL))=NIL THEN Raise("barg")
  94.   IF args.buildfile THEN StrCopy(buildfile,args.buildfile)
  95.   StrAdd(buildfile,'.build')
  96.   IF (args.nohead = 0) -> be VERY quiet
  97.     PrintF({versionString})
  98.     PrintF(' (processing "\s")\n', buildfile)
  99.   ENDIF
  100.   m,l:=readfile(buildfile)
  101.   buildtree(parse(stringsinfile(m,l,countstrings(m,l))))
  102.   IF uptodate THEN PrintF('All files are up to date.\n')
  103.   Raise()
  104. EXCEPT
  105.   IF rdargs THEN FreeArgs(rdargs)
  106.   IF exception=0 THEN RETURN
  107.   PrintF('Error: ')
  108.   SELECT exception
  109.     CASE "OPEN"
  110.       PrintF('couldn''t open "\s".\n',exceptioninfo)
  111.     CASE "MEM"
  112.       PrintF('not enough memory.\n')
  113.     CASE "IN"
  114.       PrintF('couldn''t read file.\n')
  115.     CASE "nobj"
  116.       PrintF('action without object.\n')
  117.     CASE "fexp"
  118.       PrintF('filename expected.\n')
  119.     CASE "dexp"
  120.       PrintF('":" or "=" expected.\n')
  121.     CASE "empt"
  122.       PrintF('nothing to build.\n')
  123.     CASE "circ"
  124.       PrintF('circular dependancies at file "\s".\n', exceptioninfo)
  125.     CASE "bada"
  126.       PrintF('action failed to build "\s".\n',exceptioninfo)
  127.     CASE "badd"
  128.       PrintF('dependancy "\s" not available.\n',exceptioninfo)
  129.     CASE "derr"
  130.       PrintF('child process failed.\n')
  131.     CASE "ntar"
  132.       PrintF('no such target: "\s".\n',args.target)
  133.     CASE "ndep"
  134.       PrintF('no dependancies for object "\s".\n',exceptioninfo)
  135.     CASE "clos"
  136.       PrintF('missing closing brace: "\s".\n',exceptioninfo)
  137.     CASE "cons"
  138.       PrintF('unknown constant: "\s".\n',exceptioninfo)
  139.     CASE "barg"
  140.       PrintFault(IoErr(),NIL)
  141.     CASE "scrp"
  142.       PrintF ('unable to create temporary script.\n')
  143.     DEFAULT
  144.       PrintF('burp.\n')
  145.   ENDSELECT
  146.   IF curline THEN PrintF('at line: (\d) "\s"\n',curline,curstring)
  147.   IF exception THEN PrintF('Build terminated\n')
  148.   RETURN 10
  149. ENDPROC
  150.  
  151. PROC parse(list:PTR TO LONG)
  152.   DEF l=NIL:PTR TO object, s, c, i, t, const=NIL:PTR TO constant,str:PTR TO CHAR
  153.   FOR curline:=0 TO ListLen(list)-1
  154.     s:=list[curline]
  155.     curstring:=s
  156.     c:=s[]
  157.     IF (c<>"#") AND (c<>"\0")            -> ignore?
  158.       IF (c=" ") OR (c="\t")            -> action
  159.         s:=eatwhite(s)
  160.         IF s[]
  161.           IF l=NIL THEN Raise("nobj")
  162.           -> was: l.firstaction:=NEW [l.firstaction,s]:action
  163.             -> replaced by the following IF (Rob through Glauschwuffel)
  164.             IF l.lastaction
  165.               l.lastaction.next:=NEW [NIL,s]:action
  166.               l.lastaction:=l.lastaction.next
  167.             ELSE
  168.               l.firstaction:=NEW [NIL,s]:action
  169.               l.lastaction:=l.firstaction
  170.             ENDIF
  171.         ENDIF
  172.       ELSE                    -> object rule or constant
  173.         i:=s
  174.         s:=eatname(s)
  175.         IF s=i THEN Raise("fexp")
  176.         t:=s
  177.  
  178.     IF (s[]<>":") AND (s[]<>"=") THEN Raise("dexp")
  179.         IF s[]=":"
  180.  
  181.       -> check object rule for use of constants
  182.       str:=String(1024) -> dyn. alloc., free if no constants 
  183.       IF str=NIL THEN Raise("MEM")
  184. /*      IF (substituteConstants (i, str)<>0) ->update vars if there were constants
  185.         i := str; s:=eatname(str) -> these were copied from above
  186.             IF s=i THEN Raise("fexp")
  187.             t:=s
  188.       ELSE
  189.         Dispose(str)
  190.       ENDIF
  191. */
  192.       substituteConstants (i, str)
  193.         i := str; s:=eatname(str) 
  194.             IF s=i THEN Raise("fexp")
  195.             t:=s
  196.       
  197.  
  198.           t[]:="\0"
  199.             s++
  200.           s:=eatwhite(s)
  201.           l:=NEW [l,i,NIL,NIL,0]:object
  202.           s:=eatwhite(s)
  203.           IF s[]<>"\0"
  204.             REPEAT
  205.               i:=s
  206.               s:=eatname(s)
  207.               t:=s
  208.               IF t=i THEN Raise("fexp")
  209.               s:=eatwhite(s)
  210.               t[]:="\0"
  211.               l.firstdep:=NEW [l.firstdep,i]:dependancy
  212.             UNTIL s[]="\0"
  213.           ENDIF
  214.           ELSE -> we have a constant
  215.             s++
  216.             s:=eatwhite(s)
  217.           t[]:="\0" -> terminate name
  218.       const:=NEW[const,i,s]:constant
  219.       constants:=const -> have to do it here so consts in rules are recognized
  220.           ENDIF
  221.       ENDIF
  222.     ENDIF
  223.   ENDFOR
  224.   curline:=0
  225.   IF args.constants THEN dumpC()
  226.   IF l=NIL THEN Raise("empt")
  227. ENDPROC l
  228.  
  229.  
  230. PROC eatwhite(s)
  231.   WHILE (s[]=" ") OR (s[]="\t") DO s++
  232. ENDPROC s
  233.  
  234. PROC eatname(s)
  235.   WHILE (s[]<>" ") AND (s[]<>"\t") AND (s[]<>"\0") AND (s[]<>":") AND (s[]<>"=") DO s++
  236. ENDPROC s
  237.  
  238. /* obsolete
  239. PROC execute(c)
  240. DEF s[1024]:STRING
  241.   uptodate:=FALSE
  242.   substituteConstants (c, s)
  243.   IF args.verbose THEN PrintF('\t\s\n', s)
  244. ->  PrintF('\t\s\n',IF substituteConstants (c, s) THEN s ELSE c)
  245.   IF Execute(s,NIL,stdout)=NIL THEN Raise("derr")
  246. ENDPROC */
  247.  
  248. PROC filetime(name:PTR TO CHAR)
  249.   DEF l:PTR TO filelock, fib:fileinfoblock, date:PTR TO datestamp
  250.   IF l:=Lock(name,ACTION_READ)
  251.     IF Examine(l,fib)
  252.       date:=fib.datestamp
  253.       IF fib.direntrytype<0
  254.         UnLock(l)
  255.         RETURN date.days, Shl(date.minute,12)+date.tick
  256.       ENDIF
  257.     ENDIF
  258.     UnLock(l)
  259.   ENDIF
  260. ENDPROC -1
  261.  
  262. PROC timelater(day1,tick1,day2,tick2)
  263.   IF day1>day2
  264.     RETURN TRUE
  265.   ELSEIF day1=day2
  266.     RETURN tick1>tick2
  267.   ENDIF
  268. ENDPROC FALSE
  269.  
  270. /*----------------rob's-stuff-------------------*/
  271.  
  272. PROC buildtree(list:PTR TO object) -> returns root of tree
  273.   DEF dep:PTR TO dependancy,
  274.       obj:PTR TO object
  275.  
  276.   obj:=list
  277.   WHILE obj         -> traverse objects
  278.     dep:=obj.firstdep
  279.     WHILE dep       -> traverse dependencies
  280.       dep.object:=findobject(dep.object,list)
  281.       dep:=dep.next
  282.     ENDWHILE
  283.     obj:=obj.next
  284.   ENDWHILE
  285.  
  286.   -> CHECK CYCLES!!!
  287.  
  288.   obj:=list
  289.   IF args.target
  290.     WHILE obj
  291.       IF StrCmp(args.target,obj.name) THEN JUMP out
  292.       obj:=obj.next
  293.     ENDWHILE
  294.     Raise("ntar")
  295.     out:
  296.   ELSE
  297.     IF obj THEN WHILE obj.next DO obj:=obj.next
  298.   ENDIF
  299.   traverse(obj)
  300. ENDPROC
  301.  
  302.  
  303. -> find object in list of objects by name
  304. PROC findobject(name:PTR TO CHAR,list:PTR TO object)
  305.   WHILE list
  306.     IF StrCmp(name,list.name)
  307.       -> remove object from root list
  308.       list.child:=TRUE;
  309.       RETURN list
  310.     ENDIF
  311.     list:=list.next
  312.   ENDWHILE
  313. ENDPROC NEW [NIL,name,NIL,NIL]:object
  314.  
  315. -> child-first traversal of dependancy tree
  316. PROC traverse(obj:PTR TO object) -> executes actions in tree
  317.   DEF dep:PTR TO dependancy,maxtime1=0,maxtime2=0,time1,time2,action:PTR TO action
  318.  
  319.   IF obj.firstdep OR obj.firstaction    -> object with dependancies/actions
  320.     -> traverse children and get maximum timestamp
  321.     dep:=obj.firstdep
  322.     WHILE dep
  323.       IF OstrCmp (dep.object.name, obj.name) = 0 THEN Throw("circ",obj.name) -> cyclic check by Glauschwuffel
  324.       target := obj.name
  325.       time1,time2:=traverse(dep.object)
  326.       IF timelater(time1,time2,maxtime1,maxtime2)
  327.         maxtime1:=time1
  328.         maxtime2:=time2
  329.       ENDIF
  330.       dep:=dep.next
  331.     ENDWHILE
  332.     time1,time2:=filetime (obj.name)
  333.     IF time1<0 OR timelater(maxtime1,maxtime2,time1,time2) OR args.force
  334.       -> dependancy file(s) more recent: build object
  335.       -> execute actions
  336.       action:=obj.firstaction
  337.  
  338.       buildAndExecuteScript (action)
  339.  
  340.       time1,time2:=filetime(obj.name)
  341.       IF (time1<0) AND (obj.child=TRUE) THEN Throw("bada",obj.name)
  342.     ENDIF
  343.     RETURN time1,time2
  344.   ENDIF
  345.   -> object requires no action: return timestamp
  346.   time1,time2:=filetime(obj.name);
  347.   IF time1<0 THEN Throw("badd",obj.name)
  348. ENDPROC time1,time2
  349.  
  350. /* - glauschwuffel's stuff --- */
  351.  
  352.  
  353. PROC dumpC()
  354. DEF co:PTR TO constant
  355.   co:=constants
  356.   WriteF ('Constants are:\n') 
  357.   WHILE co  
  358.     WriteF('\t<\s> with <\s>.\n', co.name, co.subst)
  359.     co:=co.next
  360.   ENDWHILE
  361. ENDPROC
  362.  
  363. PROC substituteConstants(c:PTR TO CHAR, s:PTR TO CHAR)
  364. -> search c for constants and substitute them
  365. DEF dollar, bclose=-1,sub=NIL
  366.   REPEAT
  367.     bclose++
  368.     dollar := InStr (c,'$(',bclose)
  369.     IF (dollar<>-1) -> found it?
  370.       StrAdd (s, c+bclose, dollar-bclose)
  371.       bclose := InStr (c,')',dollar+2)
  372.       IF bclose=-1 THEN Throw("clos",c)
  373.       sub := findConstant(c,dollar+2,bclose-1)
  374.       IF sub=NIL THEN Throw("cons",c+dollar)
  375.       StrAdd (s,sub)
  376.     ELSE -> copy rest of the line to buffer
  377.       StrAdd (s, c+bclose)
  378.     ENDIF
  379.   UNTIL (dollar=-1) OR (bclose=-1)
  380.   RETURN sub -> did we substitute something at all?
  381. ENDPROC
  382.  
  383. PROC findConstant(c,start,end)
  384. -> find constant of given position in list
  385. -> add 27.07.97: returns global target on target
  386. DEF co:PTR TO constant
  387.   IF OstrCmp('target',c+start,end-start+1)=0 THEN RETURN target
  388.   co:=constants
  389.   WHILE co  
  390.     EXIT (OstrCmp(co.name,c+start,end-start+1)=0)
  391.     co:=co.next
  392.   ENDWHILE
  393.   RETURN IF co THEN co.subst ELSE NIL
  394. ENDPROC
  395.  
  396. PROC buildAndExecuteScript (action:PTR TO action) HANDLE
  397. DEF s[1024]:STRING,
  398.   handle
  399.  
  400.   handle := Open ('T:Ebuild_actions', MODE_NEWFILE) -> open script file
  401.   IF (handle = NIL) THEN Raise ("scrp")
  402.  
  403.   /* create script variable TARGET */
  404.   StrCopy (s, 'Set target ')
  405.   StrAdd (s, target)
  406.   StrAdd (s, '\n') -> add newline
  407.  
  408.   Write (handle, s, StrLen (s))
  409.   IF args.verbose THEN PrintF('\t\s', s)
  410.   
  411.   WHILE action
  412.     uptodate:=FALSE
  413.     SetStr (s, 0) -> "delete" the string of the last action
  414.     substituteConstants (action.comstring, s) -> expand action
  415.     StrAdd (s, '\n') -> add newline
  416.     IF args.verbose THEN PrintF('\t\s', s)
  417.     Write (handle, s, StrLen (s))
  418.     action:=action.next
  419.   ENDWHILE
  420.  
  421.   Close (handle)
  422.   IF Execute('Execute T:Ebuild_actions', NIL, stdout)=NIL THEN Raise("derr")
  423.   DeleteFile ('T:EBuild_actions')
  424.  
  425. EXCEPT
  426.   IF handle THEN Close(handle)
  427.   ReThrow()
  428. ENDPROC
  429.  
  430.  
  431. versionTag: CHAR 0,'$VER:'
  432. versionString: CHAR 'EBuild 0.91 (05.09.97) ©1997 Rob, Wouter and Glauschwuffel',0
  433.